#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pthread.h>

#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>

// 自定义结构体类型： 客户端信息
typedef struct {
   int fd;  // 套接字
   char ip[INET_ADDRSTRLEN]; // 客户端的IP地址
   uint16_t port; // 客户端的端口号
}Client;


void *client_task(void *arg){
    
    Client *cli = (Client *)arg;
    printf("%s(%d) connected\n", cli->ip, cli->port);

    // 通信
    char buf[128] = "";
    while(1){
        bzero(buf, 128); 
        ssize_t len = recv(cli->fd, buf, 128, 0);
        if(len > 0){
            printf("%s(%d): %s\n", cli->ip, cli->port, buf);
            // 回应
            send(cli->fd, "OK", 2, 0);

            // 验证线程是否期待断开
            if(strncmp("bye", buf, 3) == 0) break;
        }
    }

    printf("%s(%d) unconnected\n", cli->ip, cli->port);
    close(cli->fd); // 关闭客户端连接通道
    free(cli);
    return NULL;
}

// ./aiserver <port>
int main(int argc, char const *argv[])
{
    if(argc != 2) return -1;

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in bind_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(atoi(argv[1])),
        .sin_addr.s_addr = INADDR_ANY
    };

    // 绑定本地网卡
    if(bind(sockfd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0){
        printf("绑定失败: %s\n", strerror(errno));
        return -1;
    }

    listen(sockfd, 10);  // 设置监听最大连接数

    printf("---AIServer running(Ctrl+C退出)---\n");
    while(1){
        // 等待客户端连接
        struct  sockaddr_in cli_addr;
        socklen_t cli_addr_len = sizeof(cli_addr);

        Client *client_p = (Client *)calloc(1, sizeof(Client));

        client_p->fd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_addr_len);
       
        // 有客户连接： 收集客户端信息（传入到客户端线程任务函数中）
        inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, client_p->ip, 16); // 将客户端的地址IP值转化字符串
        client_p->port = ntohs(cli_addr.sin_port); // 获取客户端的端口号

        pthread_t tid;
        pthread_create(&tid, NULL, client_task, client_p);  // 创建客户端通信的线程
        sleep(1);
    }
    return 0;
}
